﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Threading;

namespace EffectLibrary {
    public static class Animate {
        public static Storyboard[] Union(this Storyboard sb,params Storyboard[] sbs) {
            var v1 = sbs.ToList();
            v1.Insert(0,sb);
            return v1.ToArray();
        }
        public static void RunAll(this Storyboard[] sbs) {
            var count = sbs.Length - 1;
            var index = 1;
            EventHandler eh = default(EventHandler);
            eh = (o,k) => {
                sbs[index].Begin();
                sbs[index - 1].Completed -= eh;
                if (index < count)
                    index++;
            };
            for (int i = 0 ; i < count ; i++) {
                sbs[i].Completed += eh;
            }
            sbs[0].Begin();
        }
        public static Storyboard GetProjectionAnimateTo(this FrameworkElement fe,PlaneProjection pp,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.QuinticEase,Func<double,double> func = null) {
            var ppo = fe.Projection as PlaneProjection;
            if (ppo == null) {
                ppo = new PlaneProjection();
                fe.Projection = ppo;
            }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationX)",ppo.CenterOfRotationX,pp.CenterOfRotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationY)",ppo.CenterOfRotationY,pp.CenterOfRotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationZ)",ppo.CenterOfRotationZ,pp.CenterOfRotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetX)",ppo.GlobalOffsetX,pp.GlobalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetY)",ppo.GlobalOffsetY,pp.GlobalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetZ)",ppo.GlobalOffsetZ,pp.GlobalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetX)",ppo.LocalOffsetX,pp.LocalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetY)",ppo.LocalOffsetY,pp.LocalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetZ)",ppo.LocalOffsetZ,pp.LocalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationX)",ppo.RotationX,pp.RotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationY)",ppo.RotationY,pp.RotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationZ)",ppo.RotationZ,pp.RotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        public static Storyboard GetProjectionAnimateBy(this FrameworkElement fe,PlaneProjection pp,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.QuinticEase,Func<double,double> func = null) {
            var ppo = fe.Projection as PlaneProjection;
            if (ppo == null) {
                ppo = new PlaneProjection();
                fe.Projection = ppo;
            }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationX)",pp.CenterOfRotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationY)",pp.CenterOfRotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationZ)",pp.CenterOfRotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetX)",pp.GlobalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetY)",pp.GlobalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetZ)",pp.GlobalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetX)",pp.LocalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetY)",pp.LocalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetZ)",pp.LocalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationX)",pp.RotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationY)",pp.RotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationZ)",pp.RotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        public static Storyboard GetProjectionAnimateFt(this FrameworkElement fe,PlaneProjection ppo,PlaneProjection pp,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.QuinticEase,Func<double,double> func = null) {
            fe.Projection = new PlaneProjection();
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationX)",ppo.CenterOfRotationX,pp.CenterOfRotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationY)",ppo.CenterOfRotationY,pp.CenterOfRotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.CenterOfRotationZ)",ppo.CenterOfRotationZ,pp.CenterOfRotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetX)",ppo.GlobalOffsetX,pp.GlobalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetY)",ppo.GlobalOffsetY,pp.GlobalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.GlobalOffsetZ)",ppo.GlobalOffsetZ,pp.GlobalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetX)",ppo.LocalOffsetX,pp.LocalOffsetX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetY)",ppo.LocalOffsetY,pp.LocalOffsetY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.LocalOffsetZ)",ppo.LocalOffsetZ,pp.LocalOffsetZ,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationX)",ppo.RotationX,pp.RotationX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationY)",ppo.RotationY,pp.RotationY,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.Projection).(PlaneProjection.RotationZ)",ppo.RotationZ,pp.RotationZ,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        //
        public static Storyboard GetTransformAnimateTo(this FrameworkElement fe,CompositeTransform ct,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.BackEase,Func<double,double> func = null) {
            var cto = fe.RenderTransform as CompositeTransform;
            if (cto == null) {
                cto = new CompositeTransform();
                fe.RenderTransform = cto;
            }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateX)",cto.TranslateX,ct.TranslateX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateY)",cto.TranslateY,ct.TranslateY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewX)",cto.SkewX,ct.SkewX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewY)",cto.SkewY,ct.SkewY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleX)",cto.ScaleX,ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleY)",cto.ScaleY,ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.Rotation)",cto.Rotation,ct.Rotation,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        public static Storyboard GetTransformAnimateBy(this FrameworkElement fe,CompositeTransform ct,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.BackEase,Func<double,double> func = null) {
            var cto = fe.RenderTransform as CompositeTransform;
            if (cto == null) {
                cto = new CompositeTransform();
                fe.RenderTransform = cto;
            }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateX)",ct.TranslateX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateY)",ct.TranslateY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewX)",ct.SkewX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewY)",ct.SkewY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleX)",ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleY)",ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.Rotation)",ct.Rotation,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        public static Storyboard GetTransformAnimateFt(this FrameworkElement fe,CompositeTransform cto,CompositeTransform ct,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.BackEase,Func<double,double> func = null) {
            //(FrameworkElement.RenderTransform).(MatrixTransform.Matrix).(Matrix.M11)
            fe.RenderTransform = new CompositeTransform();
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateX)",cto.TranslateX,ct.TranslateX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.TranslateY)",cto.TranslateY,ct.TranslateY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewX)",cto.SkewX,ct.SkewX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.SkewY)",cto.SkewY,ct.SkewY,timespan,bgtime,Easing.GetEasingFunction(et,func)),

                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleX)",cto.ScaleX,ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.ScaleY)",cto.ScaleY,ct.ScaleX,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(FrameworkElement.RenderTransform).(CompositeTransform.Rotation)",cto.Rotation,ct.Rotation,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        #region brush
        public static Storyboard GetBackgroundAnimateTo(this Panel fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Background as SolidColorBrush;
            if (scb == null) { scb = new SolidColorBrush(Colors.Transparent); fe.Background = scb; }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Panel.Background).(SolidColorBrush.Color)",scb.Color,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetBackgroundAnimateBy(this Panel fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Background as SolidColorBrush;
            if (scb == null) { scb = new SolidColorBrush(Colors.Transparent); fe.Background = scb; }
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Panel.Background).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetBackgroundAnimateTo(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Background as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.Background).(SolidColorBrush.Color)",scb.Color,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetBackgroundAnimateBy(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Background as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.Background).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetForegroundAnimateTo(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Foreground as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.Foreground).(SolidColorBrush.Color)",scb.Color,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetForegroundAnimateBy(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Foreground as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.Foreground).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetBorderBrushAnimateTo(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.BorderBrush as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(SolidColorBrush.Color)",scb.Color,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetBorderBrushAnimateBy(this Control fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.BorderBrush as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }

        public static Storyboard GetStrokeAnimateBy(this Shape fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Stroke as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Shape.Stroke).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }

        public static Storyboard GetFillAnimateTo(this Shape fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Fill as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Shape.Fill).(SolidColorBrush.Color)",scb.Color,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetFillAnimateBy(this Shape fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var scb = fe.Fill as SolidColorBrush;
            if (scb == null) return null;
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Shape.Fill).(SolidColorBrush.Color)",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        //

        public static Storyboard GetBackgroundAnimateTo(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Background as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Background).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),lgb.GradientStops[i].Color,tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Background).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),lgb.GradientStops[i].Offset,tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Background).(LinearGradientBrush.StartPoint)",lgb.StartPoint,tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Background).(LinearGradientBrush.EndPoint)",lgb.EndPoint,tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }

        public static Storyboard GetBackgroundAnimateBy(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Background as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Background).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Background).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Background).(LinearGradientBrush.StartPoint)",tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Background).(LinearGradientBrush.EndPoint)",tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }
        public static Storyboard GetForegroundAnimateTo(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Foreground as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Foreground).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),lgb.GradientStops[i].Color,tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Foreground).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),lgb.GradientStops[i].Offset,tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Foreground).(LinearGradientBrush.StartPoint)",lgb.StartPoint,tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Foreground).(LinearGradientBrush.EndPoint)",lgb.EndPoint,tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }
        public static Storyboard GetForegroundAnimateBy(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Foreground as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Foreground).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.Foreground).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Foreground).(LinearGradientBrush.StartPoint)",tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.Foreground).(LinearGradientBrush.EndPoint)",tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }

        public static Storyboard GetBorderBrushAnimateTo(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.BorderBrush as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.BorderBrush).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),lgb.GradientStops[i].Color,tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.BorderBrush).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),lgb.GradientStops[i].Offset,tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(LinearGradientBrush.StartPoint)",lgb.StartPoint,tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(LinearGradientBrush.EndPoint)",lgb.EndPoint,tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }
        public static Storyboard GetBorderBrushAnimateBy(this Control fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.BorderBrush as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.BorderBrush).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Control.BorderBrush).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(LinearGradientBrush.StartPoint)",tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Control.BorderBrush).(LinearGradientBrush.EndPoint)",tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }

        public static Storyboard GetStrokeAnimateTo(this Shape fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Stroke as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Stroke).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),lgb.GradientStops[i].Color,tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Stroke).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),lgb.GradientStops[i].Offset,tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Stroke).(LinearGradientBrush.StartPoint)",lgb.StartPoint,tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Stroke).(LinearGradientBrush.EndPoint)",lgb.EndPoint,tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }
        public static Storyboard GetStrokeAnimateBy(this Shape fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Stroke as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Stroke).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Stroke).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Stroke).(LinearGradientBrush.StartPoint)",tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Stroke).(LinearGradientBrush.EndPoint)",tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }
        //test ok
        public static Storyboard GetFillAnimateTo(this Shape fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Fill as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Fill).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),lgb.GradientStops[i].Color,tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Fill).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),lgb.GradientStops[i].Offset,tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Fill).(LinearGradientBrush.StartPoint)",lgb.StartPoint,tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Fill).(LinearGradientBrush.EndPoint)",lgb.EndPoint,tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }

        public static Storyboard GetFillAnimateBy(this Shape fe,LinearGradientBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var lgb = fe.Fill as LinearGradientBrush;
            if (lgb == null || lgb.GradientStops.Count != tv.GradientStops.Count) return null;
            var count = tv.GradientStops.Count;
            var ps = new List<Tuple<string,dynamic,double,double,EasingFunctionBase>>();
            for (int i = 0 ; i < count ; i++) {
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Fill).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Color)",i),tv.GradientStops[i].Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
                ps.Add(Engine.pEngine.GetAnimateParam(string.Format("(Shape.Fill).(LinearGradientBrush.GradientStops)[{0}].(GradientStop.Offset)",i),tv.GradientStops[i].Offset,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            }
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Fill).(LinearGradientBrush.StartPoint)",tv.StartPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            ps.Add(Engine.pEngine.GetAnimateParam("(Shape.Fill).(LinearGradientBrush.EndPoint)",tv.EndPoint,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            var sb = Engine.pEngine.GetAnimation(fe,time,ps.ToArray());
            return sb;
        }

        public static Storyboard GetStrokeThicknessAnimateTo(this Shape fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("Shape.StrokeThickness",fe.StrokeThickness,tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        public static Storyboard GetStrokeThicknessAnimateBy(this Shape fe,SolidColorBrush tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("Shape.StrokeThickness",tv.Color,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }

        #endregion
        public static Storyboard GetOpacityAnimate(this FrameworkElement fe,double tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.ElasticEase,Func<double,double> func = null) {
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("FrameworkElement.Opacity",fe.Opacity,tv,timespan,bgtime,Easing.GetEasingFunction(et,func)));
            return sb;
        }
        //
        public static Storyboard GetLocationAnimate(this FrameworkElement fe,Point tv,double timespan = 500,double bgtime = 0.0,double time = 1,Easing.Type et = Easing.Type.QuinticEase,Func<double,double> func = null) {
            var sb = Engine.pEngine.GetAnimation(fe,time,
                Engine.pEngine.GetAnimateParam("(Canvas.Top)",Canvas.GetTop(fe),tv.Y,timespan,bgtime,Easing.GetEasingFunction(et,func)),
                Engine.pEngine.GetAnimateParam("(Canvas.Left)",Canvas.GetLeft(fe),tv.X,timespan,bgtime,Easing.GetEasingFunction(et,func))
                );
            return sb;
        }
        /// <summary>
        /// canvas上的粒子特效 
        /// </summary>
        /// <param name="panel">画布</param>
        /// <param name="location">可以是Mouse的点击位置</param>
        /// <paparam name="a">逆径向加速度</paparam>
        /// <pparam name="timespan">粒子效果总计划时间</pparam>
        /// <paparam name="v0">径向初速度</paparam>
        public static void ParticleEffects(this Canvas panel,Point location,double timespan = 4000,double v0 = 20,double a = 5) {
            var random = new Random();
            var span = 40;
            var timer = new DispatcherTimer {
                Interval = TimeSpan.FromMilliseconds(span),
            };
            var particlepool = new Dictionary<int,Ellipse[]>();
            var particlepoolpoint = 0;
            var brushs = new SolidColorBrush[9];
            brushs[0] = new SolidColorBrush(Colors.Blue);
            brushs[1] = new SolidColorBrush(Colors.Brown);
            brushs[2] = new SolidColorBrush(Colors.Cyan);
            brushs[3] = new SolidColorBrush(Colors.Gray);
            brushs[4] = new SolidColorBrush(Colors.Green);
            brushs[5] = new SolidColorBrush(Colors.Magenta);
            brushs[6] = new SolidColorBrush(Colors.Orange);
            brushs[7] = new SolidColorBrush(Colors.Yellow);
            brushs[8] = new SolidColorBrush(Colors.Purple);
            var mark = timespan / span;
            timer.Tick += (o,k) => {
                var sb = new Storyboard();
                if (particlepoolpoint >= mark) {
                    timer.Stop();
                }
                var particlecount = random.Next(20,30);
                var current_particles = new Ellipse[particlecount];
                sb.Children.Clear();
                for (int i = 0 ; i < particlecount ; i++) {
                    var redius = random.Next(3,6);
                    current_particles[i] = new Ellipse {
                        Height = redius, Width = redius, Fill = brushs[random.Next(0,9)],
                        Tag = random.Next(0,359) + random.NextDouble(),
                    };
                    var da = new DoubleAnimation {
                        From = 1, To = 0, Duration = new Duration(TimeSpan.FromMilliseconds(timespan - (particlepoolpoint * 40d))),
                    };
                    Storyboard.SetTargetProperty(da,new PropertyPath("Ellipse.Opacity"));
                    Storyboard.SetTarget(da,current_particles[i]);
                    sb.Children.Add(da);
                    panel.Children.Add(current_particles[i]);
                }
                sb.Begin();
                particlepool.Add(particlepoolpoint,current_particles); particlepoolpoint++;
                for (int i = 0 ; i < particlepoolpoint ; i++) {
                    for (int j = 0 ; j < particlepool[i].Length ; j++) {
                        if (particlepool[i][j].Opacity == 0) {
                            panel.Children.Remove(particlepool[i][j]);
                        }
                        double t = (particlepoolpoint - i) * 40d / 1000d;
                        var vt = v0 - t * a;//即时速度
                        var angle = (double)particlepool[i][j].Tag;
                        var vx = Math.Cos(angle) * vt;
                        var vy = Math.Sin(angle) * vt;
                        var sx = (vx + Math.Cos(angle) * v0) / 2 * t;
                        var sy = (vy + Math.Sin(angle) * v0) / 2 * t;
                        Canvas.SetLeft(particlepool[i][j],sx + location.X);
                        Canvas.SetTop(particlepool[i][j],sy + location.Y);
                    }
                }
            };
            timer.Start();
        }
    }
}
